Just to annoy Oogabooga and Adak, here are two helper functions I like to use:
Code:
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
char *strdups(const size_t strings, ...)
{
char *string, *s;
const char *source;
size_t total, len, i;
va_list args;
/* Find out the total length. */
va_start(args, strings);
total = 0;
for (i = 0; i < strings; i++) {
source = va_arg(args, const char *);
if (source)
total += strlen(source);
}
va_end(args);
/* Allocate memory for the new string, plus a '\0'. */
string = malloc(total + 1);
if (!string) {
errno = ENOMEM;
return NULL;
}
/* Copy source strings. */
va_start(args, strings);
s = string;
for (i = 0; i < strings; i++) {
source = va_arg(args, const char *);
if (!source)
continue;
len = strlen(source);
if (len < 1)
continue;
memcpy(s, source, len);
s += len;
}
va_end(args);
/* Terminate the new string. */
*s = '\0';
return string;
}
char *pathdups(const size_t components, ...)
{
char *path;
const char *part;
size_t total, n, i;
va_list args;
/* Sum component lengths. */
total = components; /* Reserve / for each component. */
va_start(args, components);
for (i = 0; i < components; i++) {
part = va_arg(args, const char *);
if (part)
total += strlen(part);
}
va_end(args);
/* Allocate memory for the resulting path. */
path = malloc(total + 2);
if (!path) {
errno = ENOMEM;
return NULL;
}
/* Copy path components. */
total = 0;
va_start(args, components);
for (i = 0; i < components; i++) {
part = va_arg(args, const char *);
if (!part)
continue;
n = strlen(part);
if (n < 1)
continue;
if (total > 0 && path[total - 1] != '/')
path[total++] = '/';
memcpy(path + total, part, n);
total += n;
}
va_end(args);
/* Terminate the path. */
path[total] = '\0';
/* Combine multiple slashes to one. */
i = n = 0;
while (i < total) {
if (path[i] == '/') {
while (path[i] == '/')
i++;
path[n++] = '/';
} else
path[n++] = path[i++];
}
path[n] = '\0';
return path;
}
Both functions use the same interface, with the number of strings first, followed by the strings themselves as separate parameters. (The functions are "variadic"; they can take a variable number of parameters.)
strdups() returns a dynamically allocated string containing concatenated copies of the source strings.
pathdups() constructs a path by concatenating directory and file names. Slashes are automatically inserted between parameters, and multiple consecutive slashes combined to a single one. (If you want to make sure you get an absolute path, prepend "/" as the first string.) For example,
Code:
char *myappconfig;
myappconfig = pathdups(2, getenv("HOME"), ".myappconfig");
if (!myappconfig) {
fprintf(stderr, "Out of memory.\n");
exit(1);
}
If environment variable HOME is undefined or empty, myappconfig will be ".myappconfig". If HOME is say /home/user, then myappconfig will be "/home/user/.myappconfig". It is a very useful function when combining more complex paths, and does not need the programmer to think about where to insert slashes or not.
While the strcat()+strdup() solution can easily overflow the buffer, strdups() and pathdups() always allocate a long enough buffer dynamically. They are thread-safe, as long as you don't modify those same source strings while another thread is calling strdups() or pathdups() .